package leetcode.pre150;

/**
 * 给定一个数组，它的第 i 个元素是一支给定股票第 i 天的价格。
 * <p>
 * 设计一个算法来计算你所能获取的最大利润。
 * <p>
 * 你可以尽可能地完成更多的交易（多次买卖一支股票）。
 * <p>
 * 注意：你不能同时参与多笔交易（你必须在再次购买前出售掉之前的股票）。
 * <p>
 *  
 * <p>
 * 示例 1:
 * <p>
 * 输入: [7,1,5,3,6,4]
 * 输出: 7
 * 解释: 在第 2 天（股票价格 = 1）的时候买入，在第 3 天（股票价格 = 5）的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
 *      随后，在第 4 天（股票价格 = 3）的时候买入，在第 5 天（股票价格 = 6）的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
 * <p>
 * 示例 2:
 * <p>
 * 输入: [1,2,3,4,5]
 * 输出: 4
 * 解释: 在第 1 天（股票价格 = 1）的时候买入，在第 5 天 （股票价格 = 5）的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
 *      注意你不能在第 1 天和第 2 天接连购买股票，之后再将它们卖出。
 *      因为这样属于同时参与了多笔交易，你必须在再次购买前出售掉之前的股票。
 * 示例 3:
 * <p>
 * 输入: [7,6,4,3,1]
 * 输出: 0
 * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
 * <p>
 * 类似问题见{@link leetcode.a_总结分布.Code04_买股票问题}
 *
 * @date 2020/5/4 22:55
 */
public class Code122_股票最佳时机2 {
    /**
     * 方式1：暴力。
     * 计算与所有可能的交易组合相对应的利润，并找出它们中的最大利润。
     * 时间O(n^n),空间O(n)
     */
    public int calculate1(int prices[], int index) {
        if (index >= prices.length)
            return 0;
        int max = 0;
        //从index开始，处理
        for (int start = index; start < prices.length; start++) {
            int maxprofit = 0;
            //找比start大的i，在这时候卖出去，然后递归
            for (int i = start + 1; i < prices.length; i++) {
                if (prices[start] < prices[i]) {
                    //卖出去
                    int profit = calculate1(prices, i + 1) + prices[i] - prices[start];
                    //更新最大利润
                    maxprofit = Math.max(maxprofit, profit);
                }
            }
            //更新最终的最大利润
            if (maxprofit > max)
                max = maxprofit;
        }
        return max;
    }

    /**
     * 方式2：波峰波谷法。
     * 在波峰卖出去，在波谷买入
     */
    public int maxProfit2(int[] prices) {
        int i = 0;
        int down = prices[0];
        int up = prices[0];
        int maxprofit = 0;
        while (i < prices.length - 1) {
            //找波谷
            while (i < prices.length - 1 && prices[i] >= prices[i + 1])
                i++;
            down = prices[i];
            //找波峰
            while (i < prices.length - 1 && prices[i] <= prices[i + 1])
                i++;
            up = prices[i];
            //卖出去
            maxprofit += up - down;
        }
        return maxprofit;
    }

    /**
     * 方式3：贪心
     * 分析见笔记：
     */
    public int maxProfit(int[] prices) {
        int profit = 0;
        for (int i = 1; i < prices.length; i++) {
            //只有当后一天赚了才卖出去。
            //连续N天赚了卖出去，等价于这N天每天都卖，再买
            //an-a1 = (a2-a1)+(a3-a2)+...+(an-an-1)
            int tmp = prices[i] - prices[i - 1];
            if (tmp > 0) profit += tmp;
        }
        return profit;
    }


}
